﻿
namespace Sina.Weibo
{
    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;

    using Sina.Weibo.Operations;

    /// <summary>
    /// This class contains the public methods that WeiboConnectClient implements.
    /// The methods in this partial class implement the Task async pattern.
    /// </summary>
    public partial class WeiboConnectClient
    {
        #region Public Methods

        /// <summary>
        /// Makes a GET call to Api service.
        /// </summary>
        /// <param name="path">relative path to the resource.</param>
        /// <returns>A Task object representing the asynchronous operation.</returns>
        public Task<WeiboOperationResult> GetAsync(string path)
        {
            return this.Api(path, ApiMethod.Get, null, new CancellationToken(false));
        }

        /// <summary>
        /// Makes a GET call to Api service.
        /// </summary>
        /// <param name="path">relative path to the resource.</param>
        /// <param name="ct">a token that is used to cancel the get operation.</param>
        /// <returns>A Task object representing the asynchronous operation.</returns>
        public Task<WeiboOperationResult> GetAsync(string path, CancellationToken ct)
        {
            return this.Api(path, ApiMethod.Get, null, ct);
        }

        /// <summary>
        /// Makes a POST call to Api service
        /// </summary>
        /// <param name="path">relative path to the resource collection to which the new object should be added.</param>
        /// <param name="body">properties of the new resource in json.</param>
        /// <returns>A Task object representing the asynchronous operation.</returns>
        public Task<WeiboOperationResult> PostAsync(string path, string body)
        {
            return this.Api(path, ApiMethod.Post, body, new CancellationToken(false));
        }

        /// <summary>
        /// Makes a POST call to Api service
        /// </summary>
        /// <param name="path">relative path to the resource collection to which the new object should be added.</param>
        /// <param name="body">properties of the new resource in json.</param>
        /// <param name="ct">a token that is used to cancel the post operation.</param>
        /// <returns>A Task object representing the asynchronous operation.</returns>
        public Task<WeiboOperationResult> PostAsync(string path, string body, CancellationToken ct)
        {
            return this.Api(path, ApiMethod.Post, body, ct);
        }

        #endregion

        #region Private Methods

        private Task<WeiboOperationResult> Api(string path, ApiMethod method, string body, CancellationToken ct)
        {
            ApiOperation op = this.GetApiOperation(path, method, body);
            return this.ExecuteApiOperation(op, ct);
        }

        private Task<WeiboOperationResult> ExecuteApiOperation(ApiOperation op, CancellationToken ct)
        {
            if (this.Session == null)
            {
                throw new WeiboConnectException(ApiOperation.ApiClientErrorCode, "UserNotLoggedIn");
            }

            var tcs = new TaskCompletionSource<WeiboOperationResult>();
            op.OperationCompletedCallback = (WeiboOperationResult opResult) =>
            {
                if (opResult.IsCancelled)
                {
                    tcs.TrySetCanceled();
                }
                else if (opResult.Error != null)
                {
                    tcs.TrySetException(opResult.Error);
                }
                else
                {
                    tcs.TrySetResult(opResult);
                }
            };

            ct.Register(op.Cancel);

            op.Execute();

            return tcs.Task;
        }

        #endregion
    }
}
